#include "./Deserializer.h"
#include "../Network/UDPIO.h"

#include "../GameLogic/Objects/GameObject.h"

#include "./AddPlayer.h"
#include "./AlterBehaviourFlags.h"
#include "./LaunchEvent.h"
#include "./SetupComplete.h"
#include "./Update.h"

using namespace Commands;

Command* Deserializer::deserialize( std::string& s ) {
	std::istringstream stream( s );
	return deserialize( stream );
}

// TODO: jezeli Deserializer zaprzyjazni sie z klasami komend, to bedzie mogl im pisac bezposrednio do pol.
//       dodatkowo trzeba by zdefiniowac konstruktor domyslny a bezargumentowy dla komend.

Command* Deserializer::deserialize( std::istringstream& s ) {
	Network::UDPIO::MsgType type;
	// wyciaga typ ze strumienia
	int t;
	s >> t;
	type = (Network::UDPIO::MsgType) t;

	switch( type ) {

	case Network::UDPIO::PLAYER_EVENT: {
		unsigned char player_id;
		s >> player_id;
		char secret;
		s >> secret;
		unsigned char team;
		s >> team;
		GameLogic::Objects::GameObject::IdType::InternalNumericType tmp_id;
		s >> tmp_id;
		GameLogic::Objects::GameObject::IdType object_id( tmp_id );
		bool is_local;
		s >> is_local;
		return new AddPlayer(player_id,secret,team,object_id,is_local);
	}

	case Network::UDPIO::SET_BEHAVIOUR: {
		CommandTypes ctype;
		s >> t; t = ctype;
		GameLogic::Objects::GameObject::IdType::InternalNumericType tmp_id;
		s >> tmp_id;
		GameLogic::Objects::GameObject::IdType object_id( tmp_id );
		int behaviour_flags;
		s >> behaviour_flags;
		bool changed_by_input; // tak naprawde zawsze false, ogolnie moze redundantne
		s >> changed_by_input;
		if( ctype == ctBegin )
			return new AlterBehaviourFlags<ctBegin>(object_id,behaviour_flags,changed_by_input);
		else
			return new AlterBehaviourFlags<ctEnd>(object_id,behaviour_flags,changed_by_input);
	}

	case Network::UDPIO::EVENT: {
		LaunchEvent::EventType etype;
		s >> t; t = etype;
		GameLogic::Objects::GameObject::IdType::InternalNumericType tmp_id;
		s >> tmp_id;
		GameLogic::Objects::GameObject::IdType object_id1( tmp_id );
		s >> tmp_id;
		GameLogic::Objects::GameObject::IdType object_id2( tmp_id );
		GameLogic::Simulation* sim = Core::PvN::getInstance().getSimulation();
		GameLogic::Objects::GameObject* go1 = sim->getGameObject( object_id1 );
		GameLogic::Objects::GameObject* go2 = sim->getGameObject( object_id2 );
		return new LaunchEvent( etype, go1, go2 );
	}

	case Network::UDPIO::OBJECT_UPDATE: {
		GameLogic::Objects::GameObject::IdType::InternalNumericType tmp_id;
		s >> tmp_id;
		GameLogic::Objects::GameObject::IdType object_id( tmp_id );
		Data* data = new Data();
		s >> data->behaviour_flags;
		s >> data->facing.x;
		s >> data->facing.y;
		s >> data->position.x;
		s >> data->position.y;
		s >> data->time;
		return new Update( object_id, data );
	}
	default:
		return 0;

	}

}
